/*
 * Copyright 2008 Wink Saville
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.saville.mc;

import android.os.Handler;
import android.os.Looper;
import android.app.Service;
import com.saville.debug.Log;
import com.saville.msgcomp.*;

/*
 * An McService is-a Service that implement IMc plus mixin's the routines from
 * Mc.java. When creating an McService there are four differences and a
 * Service3:
 * 
 * 1) Extend McService instead of Service 2) Override onCreate and call
 * super.onCreate("nameString"); 3) If you override onDestroy and call
 * super.onDestroy 4) Implement processMsg(Msg msg);
 * 
 * With these changes your Service can receive asynchronous messages as well as
 * send them. It is not necessary but perfectly fine to create an IBinder using
 * aidl.
 */
abstract public class McService extends Service implements IMc {
    public Handler mHandler;

    public void onCreate(String name) {
        super.onCreate();
        if (Log.appName.compareTo("") == 0)
            Log.appName = name;
        Log.print("McService: onCreate; E");

        mMcMgr = McMgr.getInstance();

        init(name, Looper.myLooper());

        Log.print("McService: onCreate: X");
    }

    @Override
    public void onDestroy() {
        // TODO: Some cleanup?
        Log.print("McService: onDestroy; EX");
    }

    /***************************************************************************
     * MIXIN: Mc.java except the constructors
     **************************************************************************/

    /*
     * initialization routine
     */
    public void init(String name, Looper looper) {
        Log.d(df, "Mc: %s init() E", name);
        mName = name;

        // If looper is null a runtime exception will be thrown
        if (looper == null) {
            throw new RuntimeException("Mc#init: looper is null, Looper.prepare was not called");
        }
        mHandler = new McHandler(looper);

        // Register ourselves
        mMcId = mMcMgr.register(mName, this);

        // Send CMD_STARTED (Can't use McMgr.sendMsg because mMySelf isn't
        // initialized)
        Msg msg = getMsgForSelf(McConst.MC_GUID, McConst.MC_CMD_STARTED);
        msg.dstId = mMcId.id;
        queueMsg(msg);

        Log.d(df, "Mc: %s init() X", mName);
    }

    /*
     * Get name
     */
    public String getName() {
        return mName;
    }

    /*
     * Lookup the named Mc.
     * 
     * @return unique id for this Mc.
     */
    public int lookup(String name) {
        return mMcMgr.lookup(name);
    }

    /*
     * Queue message to ourselves
     */
    @Override
    public void queueMsg(Msg msg) {
        android.os.Message m = mHandler.obtainMessage();
        //msg.dstId = mMcId.id;
        m.obj = msg;
        m.sendToTarget();
    }
    
    protected Msg getMsg() {
        Msg m = mMcMgr.getMsg();
        m.srcId = mMcId.id;
        return m;
    }

    protected Msg getMsgForSelf(int guid, int cmd) {
        // TODO: Use a pool
        Msg m = getMsg();
        m.dstId = mMcId.id;
        m.guid = guid;
        m.cmd = cmd;
        return m;
    }

    protected Msg getMsg(int dstId, int guid, int cmd) {
        // TODO: Use a pool
        Msg m = getMsg();
        m.dstId = dstId;
        m.guid = guid;
        m.cmd = cmd;
        return m;
    }

    protected void retMsg(Msg msg) {
        mMcMgr.retMsg(msg);
    }

    protected Msg dupMsg(Msg msg) {
        return mMcMgr.dupMsg(msg);
    }

    protected Msg getReplyMsg(Msg msg, int status) {
        return mMcMgr.getReplyMsg(msg, status);
    }

    protected void sendMsg(Msg msg) {
        mMcMgr.sendMsg(msg);
    }

    protected void sendReplyMsg(Msg msg, int status) {
        mMcMgr.sendReplyMsg(msg, status);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.os.Handler#handleMessage(android.os.Message)
     */
    private class McHandler extends Handler {
        McHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(android.os.Message m) {
            try {
                Msg msg = (Msg) m.obj;
                processMsg(msg);
            } catch (Exception e) {
                Log.print("Mc: handleMessage; error e=%s", e);
            }
        }
    }

    protected String mName;
    protected McId mMcId;
    protected IMcMgr mMcMgr;
    protected int df = Log.VERBOSE;
}
